#pragma once

#include "base/StructType.hpp"
#include "Date.hpp"

using json = nlohmann::json;

template<typename T>
void saveAsJson(const std::string& file, const T& obj)
{
    std::ofstream(file) << std::setw(4) << nlohmann::json(obj) << '\n';
}

template<typename T>
T loadFromJson(const std::string& file)
{
    json j;
    std::ifstream(file) >> j;
    return j.get<T>();
}



template<typename T>
void logJsonStruct(const T& obj){
    json j;
    to_json(j,obj);
    std::string jsonString =  j.dump(4);
    std::cout << jsonString << std::endl;
}





inline void to_json(json& j, const DataConfig& d) {
    j = json{
            {"tableName", d.tableName},
            {"tablePath", d.tablePath},
            {"schemaSize", d.schemaSize}
    };
}
inline void from_json(const json& j, DataConfig& d) {
    j.at("tableName").get_to(d.tableName);
    j.at("tablePath").get_to(d.tablePath);
    j.at("schemaSize").get_to(d.schemaSize);
}

inline void to_json(json& j, const SystemConfig& c) {
    j = json{
            {"dataPath",    c.dataPath},
            {"undoLogPath",    c.undoLogPath},
            {"binLogPath",    c.binLogPath},
            {"redoLogPath",    c.redoLogPath},
            {"dataConfigs", c.dataConfigs}   // 这里会自动递归调用 DataConfig 的 to_json
    };
}
inline void from_json(const json& j, SystemConfig& c) {
    j.at("dataPath").get_to(c.dataPath);
    j.at("undoLogPath").get_to(c.undoLogPath);
    j.at("binLogPath").get_to(c.binLogPath);
    j.at("redoLogPath").get_to(c.redoLogPath);
    j.at("dataConfigs").get_to(c.dataConfigs);
}


inline void to_json(json &j,const std::vector<Cell> &cells, const std::vector<FieldInfo> &fieldList){
    j = json::object();                // 先得到一个空对象 {}
    for (int i = 0; i < fieldList.size(); ++i) {
        switch (fieldList.at(i).type) {
            case FieldType::INT:{
                j[fieldList.at(i).name] = cells.at(i).i64;
                break;
            }
            case FieldType::STRING:{
                j[fieldList.at(i).name] = cells.at(i).str;
                break;
            }
            case FieldType::DATETIME:{
                j[fieldList.at(i).name] = formatDatetime5(cells.at(i).datetime);
                break;
            }
            default:{

            }
        }
    }
}

inline void to_json_array(json &jrr,const std::vector<std::vector<Cell>> &cells, const std::vector<FieldInfo> &fieldList){
    jrr = json::array();
    for (const auto& row : cells) {   // 遍历每一行
        json obj;
        to_json(obj, row, fieldList);  // 把当前行变成 {}
        jrr.push_back(std::move(obj)); // 压进数组
    }
}

template<typename T>
inline void to_json_vector(json &jrr, const std::vector<T> &t){
    jrr = json::array();
    for (const auto& row : t) {   // 遍历每一行
        json obj;
        to_json(obj, row);  // 把当前行变成 {}
        jrr.push_back(std::move(obj)); // 压进数组
    }
}
inline void to_json(json& j, const FileHeader& d) {
    j = json{
            {"pageCount", d.pageCount},
            {"maxRecordNo", d.maxRecordNo},
            {"lastPage", d.lastPage},
            {"schemaCount", d.schemaCount},
            {"rootIndexPageNo", d.rootIndexPageNo}
    };
}
inline void to_json(json& j, const PageHead& d) {
    j = json{
            {"firstRecord", d.firstRecord},
            {"freeSize", d.freeSize},
            {"freeOffset", d.freeOffset},
            {"lastRecord", d.lastRecord},
            {"recordCount", d.recordCount},
            {"pageNext", d.pageNext},
            {"pagePrev", d.pagePrev},
            {"pageNo", d.pageNo},
            {"maxTrxId", d.maxTrxId},
            {"slotSize", d.slotSize},
            {"PageType", d.pageType},
            {"maxRecordNo", d.maxRecordNo}
    };
}
inline void to_json(json& j, const FieldInfo& d) {
    j = json::object();
    j["name"] = d.name;
    j["type"] = d.type;
    j["isPrimary"] = d.isPrimary;
//    j = json{
//            {"name", d.name},
//            {"type", d.type},
//            {"isPrimary", d.isPrimary},
//    };
}
inline void to_json(json& j, const Cell& d) {
    j = json::object();
    j["str"] = d.str;
    j["type"] = d.type;
    j["i64"] = d.i64;
    j["datetime"] = d.datetime;
    j["is_null"] = d.is_null;
}
inline void to_json(json& j, const SqlFilter& d) {
//    j = json::object();
//    j["value"] = d.value;
//    j["type"] = d.type;
//    j["colIndex"] = d.colIndex;
    j = json{
            {"colIndex", d.colIndex},
            {"type", d.type},
            {"value", d.value},
    };
}

inline void to_json(json& j, const UpdateSetItem& d) {
    j = json{
            {"colIndex", d.colIndex},
            {"value", d.value},
    };
}